/*
 * Created: 2024/9/4
 * Author:  hineven
 * See LICENSE for licensing.
 */

#ifndef MIRENDERER_BLOBRES_H
#define MIRENDERER_BLOBRES_H

#include "core/common.h"
#include "core/refcounted.h"
#include "core/base.h"

MI_NAMESPACE_BEGIN

// Implement the blob resource interface to produce a functioning infra.
class BlobResourceInterface : public RefCounted {
public:

    // All the functions require thread-safe implementations

    // @return may return nullptr if the blob resource is not zero-copy readable.
    virtual const void * ReadBlobZeroCopy () = 0;
    virtual void   ReadBlob (size_t size, void * data) = 0;
    virtual size_t GetSize () = 0;
    virtual void * WriteBlob (size_t size, const void * data) = 0;
    virtual size_t GetPos () const = 0;
    virtual size_t SetPos () = 0;
    virtual ~BlobResourceInterface () = default;
    virtual bool   OpenHandle (BlobResourceAccessFlags access) = 0;
    virtual void   CloseHandle (BlobResourceAccessFlags access) = 0;
};

class BlobResourceHandle : public NonCopyable {
public:
    inline BlobResourceHandle (TRef<BlobResourceInterface> blob_resource, BlobResourceAccessFlags access)
        : blob_resource_ (std::move(blob_resource)), access_ (access) {}
    inline BlobResourceHandle (BlobResourceHandle && other) noexcept
        : blob_resource_ (std::move(other.blob_resource_)), access_ (other.access_) {
        other.blob_resource_ = nullptr;
    }

    inline BlobResourceHandle & operator = (BlobResourceHandle && other) noexcept {
        if(this != &other) {
            blob_resource_ = std::move(other.blob_resource_);
            access_ = other.access_;
            other.blob_resource_ = nullptr;
        }
        return *this;
    }

    inline bool Open () {
        if(!opened_ && blob_resource_) {
            opened_ = blob_resource_->OpenHandle(access_);
        }
        return opened_;
    }
    inline void Close () {
        if(opened_ && blob_resource_) {
            blob_resource_->CloseHandle(access_);
        }
        opened_ = false;
    }
    inline bool IsValid () { return opened_; }

    const void * ReadBlobZeroCopy () ;
    void ReadBlob (size_t size, void * data) ;
    size_t GetSize () ;
    void * WriteBlob (size_t size, const void * data) ;
    size_t GetPos () const ;
    size_t SetPos () ;

    inline ~BlobResourceHandle () {
        Close();
    }

protected:

    void CheckAccess(BlobResourceAccessFlags required_access) const;

    bool opened_ = false;
    TRef<BlobResourceInterface> blob_resource_;
    BlobResourceAccessFlags access_;
};

MI_NAMESPACE_END
#endif //MIRENDERER_BLOBRES_H
